﻿using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Web.Hosting;
using System.Text;
using System.Net;
using System.Xml;
using System.Text.RegularExpressions;
using LemmaSharp;


namespace zachmanAssignment3
{
    public class Assignment3Service : IAssignment3Service
    {
        private Dictionary<String,String> dictionaryWords = new Dictionary<String,String>();
        private Boolean loadedDictionary = false;
        private List<String> urlList = new List<String>();
        private String newsRoot = "https://api.datamarket.azure.com/Bing/Search/v1/News?Query=%27";
        private String appId = "0xs0QWltjxPDuVPIr6fc2r0kaeoZooyAfxQL85VQSSY=";

        //Uses bing news service to find relevant news articles for the passed in String array of news topics
        public String[] NewsFocus(String[] news)
        {   
            for(int i=0;i<news.Length;i++)
            {
                findUrlsForTopic(news[i]);
            }
            return urlList.ToArray();
        }

        //Uses the bing new api to find news results for the passed in topic
        private void findUrlsForTopic(String topic)
        {

            WebClient request = new WebClient();
            request.Credentials = new System.Net.NetworkCredential(appId, appId);
            Stream data = request.OpenRead(newsRoot + topic + "%27");
            StreamReader reader = new StreamReader(data);
            string s = reader.ReadToEnd();

            XmlDocument xml = new XmlDocument();
            xml.LoadXml(s);
            TraverseNodes(xml.ChildNodes);
        }

        //Find all images that are embedded in the url passed in. Each image link will be returned in the String array
        public String[] ImagesInPage(String url)
        {
            Web2String.ServiceClient client = new Web2String.ServiceClient();
            return findImages(client.GetWebContent(url));
        }

        //Find all links to images in the input string
        public String[] findImages(String input)
        {
            Regex rgx = new Regex("<img src=\"(http.+?)\"", RegexOptions.IgnoreCase);
            MatchCollection matches = rgx.Matches(input);
            String[] urls = new String[matches.Count];
            if (matches.Count > 0)
            {
                int count = 0;
                foreach (Match match in matches)
                {
                    urls[count] = match.ToString().Replace("<img src=", "").Replace("\"", "");

                    count++;
                }
            }
            return urls;
        }

        //Service to removed all javascript fron the url that is passed in
        public String RemoveJavascript(String url)
        {
            Web2String.ServiceClient client = new Web2String.ServiceClient();
            String str = regexReplaceJavascript(client.GetWebContent(url));
            return str;
        }

        //Remove all javascript tags from the string input provided
        private String regexReplaceJavascript(String input)
        {
            return Regex.Replace(input, @"<script\b[^>]*>([\s\S]*?)<\/script>", "");
        }

        //Returns http references from the url that is passed in. Can be used to "crawl" the web
        public String[] UrlsInPage(String url)
        {
            Web2String.ServiceClient client = new Web2String.ServiceClient();
            return findUrls(client.GetWebContent(url));
        }

        //Use a regular expression to find all the href="http tags in the document. If you find then, then add them to the list of urls to return
        private String[] findUrls(String input)
        {
            Regex rgx = new Regex("href=\"(http.+?)\"", RegexOptions.IgnoreCase);
            MatchCollection matches = rgx.Matches(input);
            String[] urls = new String[matches.Count];
            if (matches.Count > 0)
            {
                int count = 0;
                foreach (Match match in matches)
                {
                    urls[count] = match.ToString().Replace("href=", "").Replace("\"", "");

                    count++;
                }
            }
            return urls;
        }

        //Traverse all nodes in the Bing News results and look for the new Urls
        private void TraverseNodes(XmlNodeList nodes)
        {
            foreach (XmlNode node in nodes)
            {
                if(node.Name.Equals("d:Url"))
                {
                    urlList.Add(node.InnerText);
                }
                TraverseNodes(node.ChildNodes);
            }
        }

        /**
         * Service that takes an array of words and finds their stem or root word
         */
        public String[] Stemming(String[] words)
        {
            loadString();
            Boolean stemFound = false;
            //Use the dll attached to find the root word. Does an okay job but we want to do more.
            ILemmatizer lmtz = new LemmatizerPrebuiltCompact(LemmaSharp.LanguagePrebuilt.English);
            String[] stems = new String[words.Length];
            for(int i=0;i<words.Length;i++)
            {
                words[i] = words[i].ToLower();
                stems[i] = lmtz.Lemmatize(words[i]);
                stemFound = false;
                //If the word is short already, just return
                if (stems[i].Length < 5)
                {
                    continue;
                }

                //Start at the front of the word and pick off characters and see if it is a valid word that is in our dictionary. If so, quit, this is our root word
                for (int j = 1; j < (stems[i].Length - 4); j++)
                {
                    String subString = stems[i].Substring(0, stems[i].Length - j);
                    if(dictionaryWords.ContainsKey(subString))
                    {
                        stems[i] = subString;
                        stemFound = true;
                        break;
                    }
                    else if (!lmtz.Lemmatize(stems[i]).Equals(stems[i]))
                    {
                        stems[i] = subString;
                        stemFound = true;
                        break;
                    }
                }

                //If we have not found a match yet, go ahead and start removing character from the end of the word until you find a root word
                if (!stemFound)
                {
                    for (int j = 1; j < (stems[i].Length - 4); j++)
                    {
                        int start = j;
                        int stop = stems[i].Length - j;
                        String subString = stems[i].Substring(start,stop);
                        if (dictionaryWords.ContainsKey(subString))
                        {
                            stems[i] = subString;
                            break;
                        }
                        else if (!lmtz.Lemmatize(stems[i]).Equals(stems[i]))
                        {
                            stems[i] = lmtz.Lemmatize(stems[i]);
                            break;
                        }
                    }
                }
                
                //Make one more call to the lemmatizer and then return
                stems[i] = lmtz.Lemmatize(stems[i]);
            }

            return stems;
        }

        //Loads up all our English words from the dictionary
        public void loadString()
        {
            if (!loadedDictionary)
            {
                loadedDictionary = true;
                String[] dictionaryString = System.IO.File.ReadAllLines(Path.Combine(HostingEnvironment.ApplicationPhysicalPath, "App_Data", "dictionary.txt"));
                for (int i = 0; i < dictionaryString.Length; i++)
                {
                    dictionaryWords.Add(dictionaryString[i], "test");
                }
            }
        }


        //This service removes all records for a given username from our saved searches xml file. If it has successfully 
        //found a match with the username, it returns true. If not, it returns false.
        public Boolean RemoveUserInfoFromRecords(String username)
        {
            Boolean foundUserRecord = false;
            if (username == null)
            {
                return false;
            }
            else
            {
                XmlDocument userRecords = loadUserData();
                foreach (XmlNode node in userRecords.FirstChild.ChildNodes)
                {
                    foreach (XmlNode childNode in node.ChildNodes)
                    {
                        if (childNode.InnerText == username)
                        {
                            foundUserRecord = true;
                            break;
                        }
                    }
                    if (foundUserRecord)
                    {
                        userRecords.FirstChild.RemoveChild(node);
                        break;
                    }
                    
                }
                if (foundUserRecord)
                {
                    saveUserData(userRecords);
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }

        //Save the userRecords xml document to a file in the app_data folder
        private Boolean saveUserData(XmlDocument userRecords)
        {
            try
            {
                XmlTextWriter textWriter = new XmlTextWriter(Path.Combine(HostingEnvironment.ApplicationPhysicalPath, "App_Data", "userRecords.xml"),Encoding.UTF8);
                textWriter.Formatting = Formatting.Indented;
                userRecords.WriteTo(textWriter);
                textWriter.Flush();
                textWriter.Close();
                return true;
            }
            catch (SystemException ex)
            {
                return false;
            }
        }

        //Loads the userRecords xml file to an xml document
        private XmlDocument loadUserData()
        {
            XmlDocument xml = new XmlDocument();
            try
            {
                String dictionaryString = System.IO.File.ReadAllText(Path.Combine(HostingEnvironment.ApplicationPhysicalPath, "App_Data", "userRecords.xml"));
                xml.LoadXml(dictionaryString);
                return xml;
            }
            catch (SystemException ex)
            {
                return new XmlDocument();
            }
        }
    }
}
